package com.seckill.act.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.minio.MinIOTemplate;
import com.seckill.act.mapper.ActivityMapper;
import com.seckill.act.mapper.SkuActMapper;
import com.seckill.act.pojo.Activity;
import com.seckill.act.pojo.SkuAct;
import com.seckill.act.service.SkuActService;
import com.seckill.act.service.SkuPageService;
import com.seckill.framework.mybatisplus.WrapperParse;
import com.seckill.goods.feign.SkuFeign;
import com.seckill.goods.pojo.Sku;
import com.seckill.page.feign.SkuPageFeign;
import com.seckill.search.feign.SkuInfoFeign;
import com.seckill.util.Result;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.validation.constraints.Min;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 作者
 * @since 2022-03-04
 */
@Service
@Slf4j
public class SkuActServiceImpl extends ServiceImpl<SkuActMapper, SkuAct> implements SkuActService {

    @Autowired
    private SkuActMapper skuActMapper;

    @Autowired
    private ActivityMapper activityMapper;

    @Autowired
    private SkuInfoFeign skuInfoFeign;

    @Autowired
    private SkuFeign skuFeign;

    @Autowired
    private SkuPageFeign skuPageFeign;

    /**
     * SkuAct条件+分页查询
     *
     * @param skuAct 查询条件
     * @param page   页码
     * @param size   页大小
     * @return 分页结果
     */
    @Override
    public Page<SkuAct> findPage(SkuAct skuAct, int page, int size) {
        //分页
        IPage<SkuAct> iPage = new Page<SkuAct>(page, size);
        //搜索条件构建
        QueryWrapper<SkuAct> wrapper = WrapperParse.simple(skuAct);
        //执行搜索
        return (Page<SkuAct>) skuActMapper.selectPage(iPage, wrapper);
    }

    /**
     * SkuAct分页查询
     *
     * @param page
     * @param size
     * @return
     */
    @Override
    public Page<SkuAct> findPage(int page, int size) {
        //静态分页
        IPage<SkuAct> iPage = new Page<SkuAct>(page, size);
        //分页查询
        return (Page<SkuAct>) skuActMapper.selectPage(iPage, null);
    }

    /**
     * SkuAct条件查询
     *
     * @param skuAct
     * @return
     */
    @Override
    public List<SkuAct> findList(SkuAct skuAct) {
        //构建查询条件
        QueryWrapper<SkuAct> wrapper = WrapperParse.simple(skuAct);
        //根据构建的条件查询数据
        return skuActMapper.selectList(wrapper);
    }

    /**
     * 删除
     *
     * @param id
     */
    @Override
    public void delete(String id) {
        skuActMapper.deleteById(id);
    }

    /**
     * 修改SkuAct
     *
     * @param skuAct
     */
    @Override
    public void update(SkuAct skuAct) {
        skuActMapper.updateById(skuAct);
    }

    @Autowired
    private SkuPageService skuPageService;


    /**
     * 增加SkuAct
     *
     * @param skuAct
     */
    @Override
    public void add(SkuAct skuAct) throws Exception {
        //查询活动
        Activity activity = activityMapper.selectById(skuAct.getActivityId());


        //修改每个Sku的信息
        for (Sku sku : skuAct.getSkus()) {
            sku.setSeckillBegin(activity.getBegintime());
            sku.setSeckillEnd(activity.getEndtime());
            //1普通商品，2秒杀商品
            sku.setStatus(2);
            //未锁定
            sku.setIslock(1);
            sku.setSaleNum(sku.getSeckillNum());
            sku.setAlertNum(sku.getAlertNum());
            if (sku.getSeckillBegin() != null) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHH");
                sku.setBgtime(simpleDateFormat.format(sku.getSeckillBegin()));
            }

            //修改商品信息
            skuFeign.modifyById(sku, sku.getId());

            //增加关联信息
            SkuAct newSkuAct = new SkuAct();
            newSkuAct.setActivityId(skuAct.getActivityId());
            newSkuAct.setSkuId(sku.getId());
            skuActMapper.insert(newSkuAct);

        }
//        List<Sku> skuList = null;
//        if (CollUtil.isNotEmpty(skuAct.getSkus())) {
//            //生成静态页面
//            //skuPage(skuAct.getSkus());//单线程本类中进行静态化操作
//            String name = Thread.currentThread().getName();
//            log.info("开始执行静态化操作,当前主线程为: {}", name);
//            //这个地方是异步,但是主线程会继续执行,如果主线程接下来需要用到返回结果,想用的数据区可能为null或者部分null
//            //所以这种情况,正常需要异步线程都执行完毕后主线程才能继续执行下去
//            //所以这种异步方式不是很好,因为无法知道什么时候异步线程全部执行完毕
//            //skuPageService.skuPage(skuAct.getSkus());
//
//            //最终解决办法
//            //使用计数器 + CompletableFuture
//            //既可以实现异步线程执行任务,也可以异步获取结果,不会阻塞主线程
//
////            CompletableFuture.supplyAsync(() ->
////                    {
////                        try {
////                            return skuPageService.skuPage(skuAct.getSkus());
////                        } catch (IOException e) {
////                            e.printStackTrace();
////                            throw new RuntimeException(e);
////                        }
////                    }
////            ).whenCompleteAsync((result, ex) -> {
////                if (ex != null) {
////                    //出现异常了
////                    throw new RuntimeException("异步静态化出现异常,原因为:" + ex.getMessage());
////                }
////                if (ObjectUtil.isNotEmpty(result)) {
////                    //更新到商品表中
////                    skuAct.getSkus().stream().forEach(sku -> {
////                        //此处可以不用,生成的方法中已经打印日志了
////                        log.info("商品" + sku.getId() + "的静态化地址为: {}", sku.getHtmlUrl());
////                        skuFeign.modifyById(sku, sku.getId());
////                    });
////                }
////            });
////        }
//            skuList = skuPageFeign.batchHtml(skuAct.getSkus());
//            skuList.stream().forEach(sku -> skuFeign.modifyById(sku, sku.getId()));
//        }


//        if (CollectionUtil.isNotEmpty(skuAct.getSkus())) {
//            CompletableFuture.supplyAsync(() -> {
//                //同步数据到ES
//                log.info("批量导入数据到索引库, 线程{}执行--------", Thread.currentThread().getName());
//                try {
//                    //return skuInfoFeign.batchAddIndex(skuAct.getSkus());
//                    return skuInfoFeign.batchAddIndex(skuAct.getSkus());
//                } catch (IOException e) {
//                    e.printStackTrace();
//                    throw new RuntimeException("同步出现异常,原因为:" + e.getMessage());
//                }
//            });
//        }
    }

    @Autowired
    private Configuration configuration;


    @Autowired
    private MinIOTemplate minIOTemplate;

    /**
     * 为秒杀商品生成静态详情页面
     *
     * @param skus
     */
//    @Async
//    public void skuPage(List<Sku> skus) throws IOException {
//        log.info("生成静态详情页面线程:{}", Thread.currentThread().getName());
//        //1. 加载商品静态页面模板
//        Template template = configuration.getTemplate("item.ftl");
//        //2. 遍历获取每一个商品, 为每一个商品生成静态页面
//        skus.stream().forEach(sku -> {
//            //封装数据模型
//            Map<String, Object> dataModel = new HashMap<>(1);
//            dataModel.put("sku", sku);
//            //生成静态页面
//            try {
//                //输出静态文件到本地
//                template.process(dataModel, new FileWriter("D:\\code\\project\\seckill-web\\nginx-seckill\\seckill-app\\pages\\items" + sku.getId() + ".html"));
//                System.out.println("D:\\code\\project\\seckill-web\\nginx-seckill\\seckill-app\\pages\\items" + sku.getId() + ".html");
//                //如果是利用nginx存储和调用则
//                String url = "http://app-seckill-java.itheima.net/items/" + sku.getId() + ".html";
//                //先输出数据到内存
//                StringWriter writer = new StringWriter();
//                template.process(dataModel, writer);
//                //再将内存数据加载成输入流
//                String str = writer.getBuffer().toString();
//                ByteArrayInputStream inputStream = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8));
//                //输出静态文件到minio
//                //String url = minIOTemplate.uploadHtmlFile("html", sku.getId() + ".html", inputStream);
//                //将url封装到商品对象中
//                sku.setHtmlUrl(url);
//                System.out.println(url);
//            } catch (Exception e) {
//                throw new RuntimeException(e);
//            }
//        });
//    }
    //存到nginx里面:缺点,数量大的时候不适用
//    public void skuPage(List<Sku> skus) throws IOException {
//        if (CollUtil.isEmpty(skus)) {
//            return;
//        }
//        //获取模板
//        Template template = configuration.getTemplate("item.ftl");
//        skus.stream().forEach(sku -> {
//            Map<String, Object> dataModel = new HashMap<>(1);
//            dataModel.put("sku", sku);
//            //将数据填充到模板中
//            try {
//                template.process(dataModel, new FileWriter("D:\\code\\project\\seckill-web\\nginx-seckill\\seckill-app\\pages\\items" + sku.getId() + ".html"));
//                log.info("存储到nginx相关目录下,文件路径为: {}", "D:\\code\\project\\seckill-web\\nginx-seckill\\seckill-app\\pages\\items" + sku.getId() + ".html");
//                sku.setHtmlUrl("http://app-seckill-java.itheima.net/items/" + sku.getId() + ".html");
//            } catch (Exception e) {
//                throw new RuntimeException("商品" + sku.getId() + "静态化数据失败, 原因为:" + e.getMessage());
//            }
//        });
//    }

    //存到MinIO中
    public void skuPage(List<Sku> skus) throws IOException {
        if (CollUtil.isEmpty(skus)) {
            return;
        }
        //获取模板
        Template template = configuration.getTemplate("item.ftl");
        skus.stream().forEach(sku -> {
            Map<String, Object> dataModel = new HashMap<>(1);
            dataModel.put("sku", sku);
            //将数据填充到模板中
            try {
                //创建输出流
                //将模板中的数据导入到这个输出流中
                StringWriter stringWriter = new StringWriter();
                template.process(dataModel, stringWriter);
                String html = stringWriter.getBuffer().toString();

                //再将数据输出到MinIO中即可
                String minIOUrl = minIOTemplate.uploadHtmlFile("html", sku.getId() + ".html", new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8)));
                log.info(minIOUrl);
                sku.setHtmlUrl(minIOUrl);
            } catch (Exception e) {
                throw new RuntimeException("商品" + sku.getId() + "静态化数据失败, 原因为:" + e.getMessage());
            }
        });
    }

    /**
     * 根据ID查询SkuAct
     *
     * @param id
     * @return
     */
    @Override
    public SkuAct findById(String id) {
        return skuActMapper.selectById(id);
    }

    /**
     * 查询SkuAct全部数据
     *
     * @return
     */
    @Override
    public List<SkuAct> findAll() {
        return skuActMapper.selectList(null);
    }

    @Override
    public void deleteAll() {
        skuActMapper.delete(null);
    }

    /***
     * 增加活动下的商品
     * @param activity
     * @param skuList
     */
    @Override
    public void addList(Activity activity, List<Sku> skuList) throws Exception {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (Sku sku : skuList) {
            SkuAct skuAct = new SkuAct();
            skuAct.setSkuId(sku.getId());
            skuAct.setActivityId(activity.getId());
            skuAct.setIsDel(1);
            skuActMapper.insert(skuAct);

            //更新状态
            sku.setSeckillBegin(activity.getBegintime());
            sku.setSeckillEnd(activity.getEndtime());
            sku.setSeckillPrice(sku.getPrice() - 10);
            sku.setStatus(2);
            skuFeign.modifyById(sku, sku.getId());
            //添加数据到索引库
            skuInfoFeign.modifySku(2, sku);
            //创建静态页
            //skuPageFeign.html(sku.getId());
        }
    }

    @Override
    public void deleteAllIndex() {
        skuInfoFeign.deleteAll();
    }

    @Override
    public List<String> findSkuById(String id) {
        return skuActMapper.findSkuById(id);
    }

    @Override
    public Page<SkuAct> findPageByAcid(String acid, int page, int size) {
        //分页
        IPage<SkuAct> iPage = new Page<SkuAct>(page, size);
        //搜索条件构建
        QueryWrapper<SkuAct> wrapper = WrapperParse.simpleColumn("activity_id", acid);
        wrapper.orderByDesc("create_time");
        return (Page<SkuAct>) skuActMapper.selectPage(iPage, wrapper);
    }
}
